﻿Imports Co9320.NamaAlert.Model
Imports System.Security

Public Class UserData
    Implements ISystemMessageSender, IDisposable

#Region "Event"
    Public Event SendSystemMessage(ByVal sender As Object, ByVal e As Model.SystemMessageEventArgs) Implements Model.ISystemMessageSender.SendSystemMessage
    Protected Overridable Sub OnSendSystemMessage(ByVal e As SystemMessageEventArgs)
        RaiseEvent SendSystemMessage(Me, e)
    End Sub
#End Region

    Private Connection As String

    Public Sub New(ByVal sdfFilePath As String)
        Try
            CopyDatabaseFile(sdfFilePath)
            If Not System.IO.File.Exists(sdfFilePath) Then
                Exit Sub
            End If

            Connection = "Data Source=" & sdfFilePath
            MigrateDatabase()

        Catch ex As Exception
            Debug.Assert(False)
        End Try
    End Sub

    Private Sub CopyDatabaseFile(ByVal path As String)
        Try
            ' フォルダ作成
            My.Computer.FileSystem.CreateDirectory(System.IO.Path.GetDirectoryName(path))

            ' コピー
            Dim applicationPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
            If Not System.IO.File.Exists(path) Then
                My.Computer.FileSystem.CopyFile(System.IO.Path.Combine(applicationPath, "namaalert.sdf"), path)
            End If

        Catch ex As Exception
            OnSendSystemMessage(New SystemMessageEventArgs(SystemMessageKind.Error, "データベースファイルのコピーに失敗しました。" & ex.Message))
        End Try

    End Sub

    Private Sub MigrateDatabase()
        Dim context = New DatabaseContext(Connection) With {.ObjectTrackingEnabled = False}

        Dim majors = From i In context.SystemInfo Where i.ParamName = "SchemaMajor" Select i.ParamValue
        Dim minors = From i In context.SystemInfo Where i.ParamName = "SchemaMinor" Select i.ParamValue

        If majors.Count = 0 OrElse minors.Count = 0 Then
            ' 
            Exit Sub
        End If

        If majors.SingleOrDefault = My.Resources.SchemaMajor AndAlso _
           minors.SingleOrDefault = My.Resources.SchemaMinor Then
            Exit Sub
        End If

        ' TODO Migrate
        ' 未実装

    End Sub

    Public Function LoadStation(ByVal id As String) As Station
        Dim context = New DatabaseContext(Connection) With {.ObjectTrackingEnabled = False}

        Dim ss = From s In context.Stations Where s.Id = id
        Try
            If ss.Count > 0 Then
                Dim sid = ss.SingleOrDefault.Id
                Dim ids = From s In context.Stations _
                          From a In context.AlertSettings _
                          Where s.Id = sid _
                          AndAlso s.AlertSettingsGuid = a.AlertSettingsGuid _
                          Select a.PluginGuid
                Return ss.SingleOrDefault.ToModel(ids.ToArray)
            Else
                Return Nothing
            End If
        Catch ex As Exception
            Debug.Assert(False)
            Return Nothing
        Finally
            context.Dispose()
        End Try
    End Function

    Public Function LoadAlertTargetPrograms() As IList(Of LiveProgram)
        Dim context = New DatabaseContext(Connection) With {.ObjectTrackingEnabled = False}

        Dim items = From p In context.LivePrograms _
                    From s In context.Stations _
                    Where p.StationId = s.Id _
                    AndAlso s.IsAlertTarget

        Dim list = New List(Of LiveProgram)
        For Each i In items

            Dim sid = i.s.Id
            Dim ids = From s In context.Stations _
                      From a In context.AlertSettings _
                      Where s.Id = sid _
                      AndAlso s.AlertSettingsGuid = a.AlertSettingsGuid _
                      Select a.PluginGuid
            Dim p = i.p.ToModel(i.s, ids.ToArray)
            list.Add(p)
        Next
        context.Dispose()
        Return list

    End Function

    Public Sub SaveLiveProgram(ByVal program As LiveProgram)
        Dim list = New List(Of LiveProgram)
        list.Add(program)
        SaveLivePrograms(list)
    End Sub

    Public Sub SaveStation(ByVal station As Station)
        Dim list = New List(Of Station)
        list.Add(station)
        SaveStations(list)
    End Sub

    Public Sub SaveLivePrograms(ByVal programs As IList(Of LiveProgram))
        Dim context = New DatabaseContext(Connection)
        Try
            For Each program In programs

                ' Delete
                Dim liveId = program.Id
                Dim stationId = program.Station.Id

                Dim ps = From p In context.LivePrograms Where p.Id = liveId OrElse p.StationId = stationId
                For Each p In ps
                    context.LivePrograms.DeleteOnSubmit(p)
                Next

                Dim ss = From s In context.Stations Where s.Id = stationId

                If ss.Count > 0 Then
                    Dim guid = ss.SingleOrDefault.AlertSettingsGuid
                    context.Stations.DeleteOnSubmit(ss.SingleOrDefault)

                    Dim ass = From a In context.AlertSettings Where a.AlertSettingsGuid = guid
                    For Each a In ass
                        context.AlertSettings.DeleteOnSubmit(a)
                    Next
                End If

                ' Insert
                Dim station = program.Station.ToEntity
                context.LivePrograms.InsertOnSubmit(program.ToEntity)
                context.Stations.InsertOnSubmit(station)

                For Each id In program.Station.PluginGuids
                    context.AlertSettings.InsertOnSubmit(New AlertSettings With {.AlertSettingsGuid = station.AlertSettingsGuid, .PluginGuid = id})
                Next

            Next

            context.SubmitChanges(Data.Linq.ConflictMode.ContinueOnConflict)
        Catch ex As Exception
            Debug.Assert(False)
        Finally
            context.Dispose()
        End Try
    End Sub

    Public Sub SaveStations(ByVal stations As IList(Of Station))
        Dim context = New DatabaseContext(Connection)
        Try
            For Each station In stations

                ' Delete
                Dim stationId = station.Id

                Dim ss = From s In context.Stations Where s.Id = stationId
                If ss.Count > 0 Then
                    Dim guid = ss.SingleOrDefault.AlertSettingsGuid
                    context.Stations.DeleteOnSubmit(ss.SingleOrDefault)

                    Dim ass = From a In context.AlertSettings Where a.AlertSettingsGuid = guid
                    For Each a In ass
                        context.AlertSettings.DeleteOnSubmit(a)
                    Next
                End If

                ' Insert
                Dim stationEntity = station.ToEntity
                context.Stations.InsertOnSubmit(stationEntity)
                For Each id In station.PluginGuids
                    context.AlertSettings.InsertOnSubmit(New AlertSettings With {.AlertSettingsGuid = stationEntity.AlertSettingsGuid, .PluginGuid = id})
                Next
            Next

            context.SubmitChanges(Data.Linq.ConflictMode.ContinueOnConflict)
        Catch ex As Exception
            Debug.Assert(False)
        Finally
            context.Dispose()
        End Try
    End Sub

#Region " IDisposable Support "
    Private disposedValue As Boolean ' 重複する呼び出しを検出するには

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' Managed Object
            End If
        End If
        disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region


End Class
